package org.example;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.stmt.AssertStmt;
import com.github.javaparser.ast.stmt.Statement;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SQLKeywordFinderWithJavaParser {

    private static final Pattern SQL_KEYWORD_PATTERN = Pattern.compile("\\b(" + String.join("|", SQLKeywords.SQL_KEYWORDS) + ")\\b", Pattern.CASE_INSENSITIVE);

    public static void findSQLKeywordsInFile(File file) {
        try{
            FileInputStream in = new FileInputStream(file);
            JavaParser javaParser = new JavaParser();
            // Parse the Java file into a CompilationUnit
            ParseResult<CompilationUnit> parseResult = javaParser.parse(in);
            if (!parseResult.isSuccessful()) {
                System.err.println("Failed to parse file: " + file.getName());
                return;
            }

            CompilationUnit cu = parseResult.getResult().get();

            // Create a visitor to traverse the AST and find SQL keywords
            cu.accept(new SQLKeywordVisitor(file.getName()), null);

        } catch (Exception e) {
            System.err.println("Error reading file: " + file.getName() + " - " + e.getMessage());
        }
    }

    // Custom visitor to find SQL keywords in the AST
    private static class SQLKeywordVisitor extends VoidVisitorAdapter<Void> {

        private final String fileName;
        private String currentClassName = null;

        public SQLKeywordVisitor(String fileName) {
            this.fileName = fileName;
        }

        @Override
        public void visit(ClassOrInterfaceDeclaration n, Void arg) {
            super.visit(n, arg);
            currentClassName = n.getNameAsString();
        }

        @Override
        public void visit(MethodDeclaration n, Void arg) {
            super.visit(n, arg);
            // Traverse all statements in the method body
            if (n.getBody().isPresent()) {
                n.getBody().get().accept(new StatementVisitor(currentClassName, fileName), null);
            }
        }
    }

    // Visitor to find SQL keywords in statements
    private static class StatementVisitor extends VoidVisitorAdapter<Void> {

        private final String className;
        private final String fileName;

        public StatementVisitor(String className, String fileName) {
            this.className = className;
            this.fileName = fileName;
        }

        @Override
        public void visit(AssertStmt n, Void arg) {
            super.visit((AssertStmt) n, arg);
            // Get the line number of the statement
            int lineNumber = n.getBegin().orElseThrow(() -> new RuntimeException("No line number")).line;

            // Convert the statement to a string and check for SQL keywords
            String statementText = n.toString();
            Matcher matcher = SQL_KEYWORD_PATTERN.matcher(statementText);
            while (matcher.find()) {
                String keyword = matcher.group();
                System.out.println("Found SQL keyword '" + keyword + "' in file: " + fileName +
                        ", class: " + className + ", line: " + lineNumber);
            }
        }
    }
}